// Every Picture In The Universe 0.1
// Started by Vander 'imerso' Nunes on July 2012
// To contact me: imerso@imersiva.com
//
// Given enough time, generates every possible
// image for a given resolution -- which includes all your
// pictures in the past, present and future, plus
// you playing guitar together with David Gilmour
// on Rock in Rio, etc.
// OK, that may take a few billion years depending
// on the selected image resolution, but hey,
// one day that will happen -- hmm well, I guess.
//
// license: http://opensource.org/licenses/lgpl-2.1
//
// Although it seems like the program is just
// randomizing pixels, this is definitely not
// the case. A linear loop is too boring,
// so I'm trying to create alternative ways
// of permute color combinations in more
// interesting ways. Some may be buggy at
// first, but eventually this will combine
// using interesting, dynamic patterns
// until something meaninful happens.
//
// Hope you get the idea.
//
// most obvious enhancements:
//
// - a start dialog to select options
// - mono and grayscale support (for way faster permutations)
// - a time control to skip directly to a given time
// - pause the simulation
// - save both the 'time' and the generated image.

#include <windows.h>
#include <math.h>
#include <stdio.h>
#include "sw_screen.h"
#include "game.h"

//
// Entry point
//
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, \
									 LPSTR lpCmdLine, int nCmdShow)
{
	MSG mMsg;

	// buffer resolution
	#define WIDTH 64
	#define HEIGHT 48

	// stretched to this window resolution
	#define WIN_WIDTH 640
	#define WIN_HEIGHT 480

	#define FULL_SCREEN 0

	#if FULL_SCREEN
		if (!g_Scr.Init(WndProc, WIDTH,HEIGHT,32, true, NULL, WIN_WIDTH,WIN_HEIGHT, "EVERY PICTURE IN THE UNIVERSE")) return false;
	#else
		if (!g_Scr.Init(WndProc, WIDTH,HEIGHT,32, false, NULL, WIN_WIDTH,WIN_HEIGHT, "EVERY PICTURE IN THE UNIVERSE")) return false;
	#endif

	g_Size = g_Scr.Width()*g_Scr.Height()*4;

	// clear zbuffer
	memset(g_Scr.ZBuffer(), 0x7FFFFFFF, g_Size);

	// clear frame-buffer
	memset(g_Scr.FrameBuffer(), 0, g_Size);

	// allocate a buffer for random ordered framebuffer access
	g_Order = new int[g_Size];

	// start with linear indexes to the framebuffer
	for (int i=0; i<g_Size; i++)
	{
		g_Order[i] = i;
	}

#if TRUE
	// randomly shuffle indexes
	for (int i=0; i<g_Size; i++)
	{
		int idx1 = (rand() + rand() * rand() + i) % (g_Size-1);
		int idx2 = (rand() + rand() * rand() + i) % (g_Size-1);
		int tmp = g_Order[idx1];
		g_Order[idx1] = g_Order[idx2];
		g_Order[idx2] = tmp;
	}
#endif

	// reset current index
	g_Idx = 0;

	// -----------------------------------------------

	while(true)
	{ 
		Sleep(1);

		if (PeekMessage(&mMsg, 0, 0, 0, PM_REMOVE))
		{
			if (mMsg.message == WM_QUIT)
				break;

			TranslateMessage(&mMsg);
			DispatchMessage(&mMsg);
		}

		Draw();
	}

	// -----------------------------------------------

	delete g_Order;

	return 0;
}


//
// Basic window procedure
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
{
	switch(uMessage)
	{
		case WM_DESTROY:
		{
			PostQuitMessage(0);
			break;
		}

		case WM_KEYDOWN:
		{
			switch (wParam)
			{
				case VK_ESCAPE:
				{
					PostMessage(hWnd,WM_CLOSE,0,0);
					break;
				}
			}
			break;
		}
	}

	return DefWindowProc(hWnd,uMessage,wParam,lParam);
}

	void Draw()
	{
		// better use 1 or powers of 2 up to 128 (which reduces color variation of course)
		#define INC_SPEED 64
		#define METHOD 1

		#if METHOD==1

			// get next "random" framebuffer index
			int p = g_Order[g_Idx];

			g_Idx++;
			if (g_Idx >= g_Size) g_Idx = 0; 

			BYTE* pFrameBuffer = g_Scr.FrameBuffer();
			pFrameBuffer[p] += INC_SPEED;

		#else

			#if METHOD==2

				int p = 0;
				BYTE* pFrameBuffer = g_Scr.FrameBuffer();
				while(p < WIDTH*HEIGHT*4)
				{
					BYTE c = pFrameBuffer[p];
					c += INC_SPEED;
					pFrameBuffer[p] = c;

					if (c == 0)
					{
						p++;
					}
					else
					{
						break;
					}
				}

			#else

				// get next "random" framebuffer index
				int p = g_Order[g_Idx];

				g_Idx++;
				if (g_Idx >= g_Size) g_Idx = 0; 

				BYTE* pFrameBuffer = g_Scr.FrameBuffer();
				pFrameBuffer[p] ^= 255;

			#endif

		#endif

		// flip screen
		g_Scr.Flip();
	}
